package opc.read.sycread;

import com.alibaba.fastjson.JSON;
import opc.read.utils.MyCopyOnWriteMap;
import opc.read.utils.ReadHostProt;
import opc.read.utils.ReadJSONItem;
import opc.read.utils.WriterFile;
import org.jinterop.dcom.common.JIException;
import org.openscada.opc.lib.common.ConnectionInformation;
import org.openscada.opc.lib.da.*;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

//import lombok.SneakyThrows;

/**
 * @Description: 测试模拟仙鹤的信号，使用异步读取
 * @author: liyuan
 * @data 2021-01-06 10:21
 */
public class ByReadUseJson3 {

    public static void DemoAPI() throws IOException {

//        final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH");

        LinkedHashMap<String, Object> xinhaoSources = ReadJSONItem.xianHe(); // 读取json信号文件，得到字符串。将字符串转成LinkedHashMap
        xinhaoSources.remove("date");

        Map<String, String> dataSources = ReadHostProt.trueHostProp();

        final ConnectionInformation ci = new ConnectionInformation();
        ci.setHost(dataSources.get("host"));
        ci.setDomain(dataSources.get("domain"));
        ci.setUser(dataSources.get("user"));
        ci.setPassword(dataSources.get("password"));
        ci.setClsid(dataSources.get("clsid"));

        final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
        final AutoReconnectController autoReconnectController = new AutoReconnectController(server);

        final Map<String, Map<String, Item>> signalSource = new LinkedHashMap<String, Map<String, Item>>(); // 存放信号源
        final MyCopyOnWriteMap<String, Object> result = new MyCopyOnWriteMap<String, Object>(new LinkedHashMap<String, Object>()); // 存放结果

        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

        try {
            // connect to server
            autoReconnectController.connect();

//            final AccessBase access = new SyncAccess(server, 1000); // 同步方式
            /***
             The RPC server is unavailable. Please check if the COM server is up and running
             Caused by: rpc.FaultException: Received fault. (unknown)
             */
            final AccessBase access = new Async20Access(server, 1000, false); // 异步方式  // Failed to change state (true).   changed()方法不被调用，导致result一直不更新

//            Group group = null;
            for (Map.Entry<String, Object> groupMap : xinhaoSources.entrySet()) {  // group
                String groupName = groupMap.getKey();
                if (groupName.equals("date")) {
                    continue;
                }
                Group group = null; // 放在这里还是放在for循环的外面？
                group = server.addGroup(groupName);
                group.setActive(true);

                String[] items = ((Map<String, Object>) groupMap.getValue()).keySet().toArray(new String[1]); // 得到信号数组
                String[] shiPeiItems = new String[items.length];
                for (int i = 0; i < items.length; i++) {
                    shiPeiItems[i] = "xianhe.设备 1." + items[i];
                }
                System.out.println(groupName);

                Map<String, Item> itemMap = group.addItems(shiPeiItems);
                signalSource.put(groupName, itemMap); // 组，组信号

                result.put(groupName, xinhaoSources.get(groupName));  // 保存结果。现在信号还是空的
            }

            //首先遍历读一遍
            result.put("date", System.currentTimeMillis());
            for (final String groupName : signalSource.keySet()) {
                Map<String, Item> itemMap = signalSource.get(groupName);
                //组内部的读取信号
                for (Map.Entry<String, Item> map : itemMap.entrySet()) {
                    if (map.getValue() instanceof Item) {
                        Item item = map.getValue();
                        Object object = item.read(false).getValue().getObject();
                        Short quality = item.read(false).getQuality();
                        if (quality < 192) object = null; // 当信号质量值小于192的时候，表示该信号有问题，该信号值赋值为null
                        ((Map<String, Object>) result.get(groupName)).put(item.getId().split("\\.")[2], object);  // 去掉xianhe.设备 1., 只留下需要的信号名
                    }
                }
            }

//            final Producer producer = KafkaSelfProducer.getProducer();
            //新开线程开始读取
            scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {

                    result.put("date", System.currentTimeMillis());

                    String jsonString = JSON.toJSONString(result);
                    System.out.println("--json---");
                    System.out.println(jsonString);

//                    System.out.println("发送数据到kafka...");
//                    producer.send(new ProducerRecord<String, String>("zhenxing0", jsonString));

                    System.out.println("将结果保存到文本文件中...");
                    WriterFile.writeTxtFile(jsonString, new File("d:/ProDataAccess/xianhe/data/file5/" + formatter.format(new Date()) + ".txt"), "utf-8");
                }
            }, 2000, 1000, TimeUnit.MILLISECONDS);

            // 因为有另外一个线程活着，所以这个线程会一直工作，不会退出。当没有起另外一个线程时，不加while(true)，程序就会退出
            int i = 0;
            for (final String groupName : signalSource.keySet()) {
                System.out.println("i : " + i++);
                Map<String, Item> itemMap = signalSource.get(groupName);
                //组内部的读取信号

                int j = 0;
                for (Map.Entry<String, Item> map : itemMap.entrySet()) {
                    System.out.println("j: " + j++);
                    if (map.getValue() instanceof Item) {
                        //读取单个数据的代码
                        access.addItem(map.getValue().getId(), new DataCallback() {
                            //                                @SneakyThrows
                            @Override
                            public void changed(Item item, ItemState state) { // 是变化了才会改变吗？为什么从结果来看，没有改变的信号也在输出？

                                // Item和ItemState的区别
                                System.out.println("--changed---");  // 为什么一直输出？？
                                try {
//                                        System.out.println(state.getValue().getObject().getClass().getName());

                                    System.out.println("name: " + item.getId().split("\\.")[2] + " ,value: " + state.getValue().getObject());
                                } catch (JIException e) {
                                    e.printStackTrace();
                                }

                                try {
//                                        if (state.getValue().getObject() instanceof Double || state.getValue().getObject() instanceof Boolean) {
                                    Map<String, Object> itemMap = (Map<String, Object>) result.get(groupName);
                                    itemMap.put(item.getId().split("\\.")[2], state.getValue().getObject());
//                                        }
                                } catch (JIException e) {
                                    e.printStackTrace();
                                }

                            }
                        });
                        access.bind();
                    }
                }
            }


//            Thread.sleep(100);

//            access.unbind();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
